package hhq.demo.wechart.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import javax.servlet.http.HttpServletRequest;

import hhq.demo.utils.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import hhq.demo.server.SseServer;
import hhq.demo.wechart.dao.MessDao;
import hhq.demo.wechart.dao.UserDao;
import hhq.demo.wechart.popj.ChartMess;
import hhq.demo.wechart.popj.ChartUser; 

/**
 * 2023 11 03 改用 SseEmitter 来实现推送
 */
@RestController
@RequestMapping("/wechart")
public class MessController {

    @Autowired
    UserDao userDao;

    @Autowired
    MessDao messDao;

    /**
     * 用户SSE连接
     * 它返回一个SseEmitter实例，这时候连接就已经创建了. 
     */
    @GetMapping("/userConnect")
    public SseEmitter connect(HttpServletRequest req) {
        /**
         * 一般取登录用户账号作为 messageId。分组的话需要约定 messageId的格式。 
         */
        ChartUser user =  (ChartUser)req.getSession().getAttribute("user");
        String userId = "userId-" + user.getUid();
        return SseServer.createConnect(userId);
    }

 
    /**
     *  发送消息
     */
    @RequestMapping(value="/send1", method = RequestMethod.POST, consumes = "multipart/form-data")
    public String send(
        @RequestParam("fromUID") String fromUID, 
        @RequestParam("toName") String toName, 
        @RequestParam("data") String data
    ){

        ChartUser toUser = userDao.queryOne(toName);
        if( toUser == null ) return "err";

        ChartMess mess = new ChartMess();
        mess.setFromUID(fromUID);
        mess.setToUID(toUser.getUid());
        mess.setType("txt");
        mess.setData(data);
        mess.setTime(System.currentTimeMillis());

        messDao.insertOne(mess); 

        send_sse_mess(toUser.getUid()); // 推送给接收方

        return "succ";
    }
    /**
     *  发送消息 包含附件
     */
    @RequestMapping(value="/send2", method = RequestMethod.POST,consumes = "multipart/form-data")
    public String send(
        @RequestParam("fromUID") String fromUID, 
        @RequestParam("toName") String toName, 
        @RequestParam("data") String data, //忽略？
        @RequestParam("file") MultipartFile file
    )  {

        ChartUser toUser = userDao.queryOne(toName);
        if( toUser == null || file.isEmpty() ) return "err";

        ChartMess mess = new ChartMess();
        mess.setFromUID(fromUID);
        mess.setToUID(toUser.getUid()); 
        mess.setType("file"); 
        byte[] by = null;
        String filename = file.getOriginalFilename();
        //清理非法名称 < > / \ | : " * ?
        filename = FileUtil.clearNotGood(filename);
        try {
            by = file.getBytes();
        } catch (Exception e) {
            return "err";
        }
        if( filename.endsWith(".mp4") ){
            mess.setType("vid"); 
        }
        mess.setData(filename);
        mess.setTime(System.currentTimeMillis()); 
        messDao.insertOne(mess);  // 插入消息
        messDao.put_byte(filename, by); // 插入附件

        send_sse_mess(toUser.getUid()); // 推送给接收方

        return "succ";
    }

    // 推送 mess, 查询出某个人的所有消息，推送
    private boolean send_sse_mess(String uid){
        JSONObject json = query_mess_json_by_uid(uid);
        if( json.getJSONArray("arr").isEmpty()){
            return false;
        }
        SseServer.sendMessage("userId-" + uid, json.toJSONString());
        return true;
    }

    // 查询一个uid的所有接收的消息
    private JSONObject query_mess_json_by_uid(String uid){
        List<ChartMess> list = messDao.queryMessByUid(uid);
        JSONObject js = new JSONObject(); // {"arr":[{},{}]}
        JSONArray arr = new JSONArray();
        
        for(ChartMess m : list){
            JSONObject one = new JSONObject(); 
            one.put("fromUID", m.getFromUID()); 
            ChartUser user = userDao.queryOne(m.getFromUID()); 
            if(user==null)
                one.put("fromName", "null");
            else
                one.put("fromName", user.getName());
            one.put("toUID", m.getToUID()); 
            one.put("type", m.getType());
            if(m.getType().equals("txt"))
                one.put("data", m.getData());
            else{
                String fn = m.getData(); // 这是文件名而已
                String url = "./download?key="+fn;
                one.put("data", url);
            }
            one.put("time", m.getTime());
            arr.add(one);
        }
        js.put("res", "succ");
        js.put("arr", arr);
        
        return js;
    }

    /**
     *  手动查询自己的收信息
     */
    @RequestMapping(value="/query_my_mess")
    public String query_my_mess(@RequestParam("uid") String uid ){
        return query_mess_json_by_uid(uid).toJSONString();
    }

    // 下载文件
    @GetMapping("/download")  
    public ResponseEntity<InputStreamResource> downloadFile(@RequestParam("key") String key ) throws IOException {   
        byte[] fileContent = messDao.get_byte(key); 
  
        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(fileContent));  
  
        return ResponseEntity.ok()  
                .contentType(MediaType.APPLICATION_OCTET_STREAM)  
                .header("Content-Disposition", "attachment; filename=" + URLEncoder.encode(key, "utf-8") )  
                .contentLength(fileContent.length) 
                .header("Content-Range", "" + Integer.valueOf(fileContent.length - 1))
                .header("Accept-Ranges", "bytes")
                .body(resource);  
    }  


}
